package com.ruoyi.quartz.util;

import java.text.DateFormatSymbols;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.springframework.scheduling.support.CronSequenceGenerator;
import org.springframework.util.StringUtils;

import lombok.extern.slf4j.Slf4j;

/**
 * @ClassName [DateUtil]
 * @Description [时间处理工具类]
 * @CreateDate [2018-10-08 11:50]
 * @Version [1.0]
 */
@Slf4j
public class DateUtil {

	public final static String yyyyMM = "yyyyMM";

	public static final String SIMPLE_FORMAT = "yyyy-MM-dd HH:mm:ss";

	public static final String FORMAT_YEAR_TO_MS = "SIMPLE_FORMATHHmmssSSS";

	public static final String FORMAT_YEAR_TO_SE = "SIMPLE_FORMATHHmmss";

	public static final String FORMAT_HOUR_TO_SE = "HHmmss";

	public static final String HIGH_SCALE_FORMAT = "yyyy-MM-dd HH:mm:ss";

	public static final String FORMAT_HOUR_TO_MI = "HHmm";

	public static final String ADVANCE_CLAIM_ON_DAY_START_TIME = "0400";

	public static final String ADVANCE_CLAIM_ON_DAY_END_TIME = "1200";

	public static final String HIGH_SCALE_FORMAT_TOMS = "yyyy-MM-dd HH:mm:ss.SSS";

	private DateUtil() {
		//no instance
	}

	/**
	 * 
	* @Title: format
	* @Description: 日期格式化，yyyy-MM-dd HH:mm:ss
	* @param date
	* @return    参数
	* @return String    返回类型
	 */
	public static String format(Date date) {
		return new SimpleDateFormat(SIMPLE_FORMAT).format(date);
	}

	/**
	 * 
	* @Title: formatHighScale
	* @Description: 日期格式化yyyy-MM-dd HH:mm:ss
	* @param date
	* @return    参数
	* @return String    返回类型
	 */
	public static String formatHighScale(Date date) {
		return new SimpleDateFormat(HIGH_SCALE_FORMAT).format(date);
	}

	/**
	 * 
	* @Title: formatHighScaleToMS
	* @Description: 日期格式化yyyy-MM-dd HH:mm:ss.SSS
	* @param date
	* @return    参数
	* @return String    返回类型
	 */
	public static String formatHighScaleToMS(Date date) {
		return new SimpleDateFormat(HIGH_SCALE_FORMAT_TOMS).format(date);
	}

	/**
	 * 
	* @Title: format
	* @Description: 日期格式化,指定格
	* @param date
	* @param format
	* @return    参数
	* @return String    返回类型
	 */
	public static String format(Date date, String format) {
		if (null == date) {
			date = new Date();
		}
		if (StringUtils.isEmpty(format)) {
			format = SIMPLE_FORMAT;
		}
		SimpleDateFormat sdf = new SimpleDateFormat(format);
		return sdf.format(date);
	}

	/**
	 * 
	* @Title: getLastMonths
	* @Description: 获取当前月之前某月
	* @param i
	* @param format
	* @return    参数
	* @return String    返回类型
	 */
	public static String getLastMonths(int i, String format) {
		if (StringUtils.isEmpty(format)) {
			format = SIMPLE_FORMAT;
		}
		SimpleDateFormat sdf = new SimpleDateFormat(format);
		Calendar c = Calendar.getInstance();
		c.setTime(new Date());
		c.add(Calendar.MONTH, -i);
		Date m = c.getTime();
		return sdf.format(m);
	}

	/**
	 * 
	* @Title: getLastYear
	* @Description: 获取当前日期前几年
	* @param i
	* @param format
	* @return    参数
	* @return String    返回类型
	 */
	public static String getLastYear(int i, String format) {
		if (StringUtils.isEmpty(format)) {
			format = SIMPLE_FORMAT;
		}
		SimpleDateFormat sdf = new SimpleDateFormat(format);
		Calendar c = Calendar.getInstance();
		c.setTime(new Date());
		c.add(Calendar.YEAR, -i);
		Date y = c.getTime();
		return sdf.format(y);
	}

	/**
	 * 
	* @Title: dayCompare
	* @Description: 计算2个日期之间相差的 以年、月、日为单位，各自计算结果是多少 比如：2011-02-02 到 2017-03-02 以年为单位相差为：6年
	 * 以月为单位相差为：73个月 以日为单位相差为：2220天
	* @param fromDate 开始时间
	* @param toDate 结束时间
	* @return DayCompare
	* @throws ParseException    参数
	* @return DayCompare    返回类型
	 */
	public static DayCompare dayCompare(String fromDate, String toDate) throws ParseException {
		SimpleDateFormat sdf = new SimpleDateFormat(yyyyMM);
		Date fDate = sdf.parse(fromDate);
		Date tDate = sdf.parse(toDate);
		Calendar from = Calendar.getInstance();
		from.setTime(fDate);
		Calendar to = Calendar.getInstance();
		to.setTime(tDate);
		// 只要年月
		int fromYear = from.get(Calendar.YEAR);
		int fromMonth = from.get(Calendar.MONTH);

		int toYear = to.get(Calendar.YEAR);
		int toMonth = to.get(Calendar.MONTH);

		int year = toYear - fromYear;
		int month = toYear * 12 + toMonth - (fromYear * 12 + fromMonth);
		int day = (int) ((to.getTimeInMillis() - from.getTimeInMillis()) / (24 * 3600 * 1000));
		return DayCompare.builder().day(day).month(month).year(year).build();
	}

	/**
	 * 
	* @Title: parse
	* @Description: 解析给定字符串开头的文本以生成日期
	* @param formatPattern
	* @param strDate
	* @return
	* @throws ParseException    参数
	* @return Date    返回类型
	* @throws ParseException
	 */
	public static Date parse(String formatPattern, String strDate) throws ParseException {
		try {
			SimpleDateFormat sdf = new SimpleDateFormat(formatPattern);
			sdf.setLenient(false);
			return sdf.parse(strDate);
		} catch (ParseException e) {
			throw new RuntimeException(e.getMessage());
		}
	}

	/**
	 * 
	* @Title: parse
	* @Description: 解析给定字符串开头的文本以生成日期
	* @param dateString
	* @return    参数
	* @return Date    返回类型
	 */
	public static Date parse(String dateString) {
		try {
			SimpleDateFormat sdf = new SimpleDateFormat(SIMPLE_FORMAT);
			sdf.setLenient(false);
			return sdf.parse(dateString);
		} catch (ParseException e) {
			throw new RuntimeException(e.getMessage());
		}
	}
	
	/**
	 * 
	* @Title: parseHighScale
	* @Description: 解析给定字符串开头的文本以生成日期，格式yyyy-MM-dd HH:mm:ss
	* @param dateString
	* @return    参数
	* @return Date    返回类型
	 */
	public static Date parseHighScale(String dateString) {
		try {
			SimpleDateFormat sdf = new SimpleDateFormat(HIGH_SCALE_FORMAT);
			sdf.setLenient(false);
			return sdf.parse(dateString);
		} catch (ParseException e) {
			throw new RuntimeException("解析给定字符串开头的文本以生成日期异常",e);
		}
	}

	/**
	 * 
	* @Title: isValidDate
	* @Description: 判断字符是否为日期
	* @param date
	* @return    参数
	* @return Boolean    返回类型
	* @throws
	 */
	public static Boolean isValidDate(String date) {
		boolean convertSuccess = true;
		String rexp = "^((\\d{2}(([02468][048])|([13579][26]))[\\-\\/\\s]?((((0?[13578])|(1[02]))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])))))|(\\d{2}(([02468][1235679])|([13579][01345789]))[\\-\\/\\s]?((((0?[13578])|(1[02]))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\\-\\/\\s]?((0?[1-9])|(1[0-9])|(2[0-8]))))))";
		SimpleDateFormat format = new SimpleDateFormat(SIMPLE_FORMAT);
		try {
			format.setLenient(false);
			format.parse(date);
			Pattern pat = Pattern.compile(rexp);
			Matcher mat = pat.matcher(date);
			convertSuccess = mat.matches();

		} catch (Exception e) {
			convertSuccess = false;
		}
		return convertSuccess;
	}
	

	/**
	 * 
	* @Title: getDaysBetween
	* @Description: 获取两个日期之间的间隔天数 str1 - str2 = ?
	* @param str1
	* @param str2
	* @return    参数
	* @return int    返回类型
	 */
	public static int getDaysBetween(String str1, String str2) {
		Calendar c1 = Calendar.getInstance(Locale.CHINA);
		Calendar c2 = Calendar.getInstance(Locale.CHINA);
		c1.setTime(parse(str1));
		c2.setTime(parse(str2));
		// 把时分秒置为0
		c1.set(Calendar.HOUR_OF_DAY, 0);
		c1.set(Calendar.MINUTE, 0);
		c1.set(Calendar.SECOND, 0);

		c2.set(Calendar.HOUR_OF_DAY, 0);
		c2.set(Calendar.MINUTE, 0);
		c2.set(Calendar.SECOND, 0);

		return (int) (((c1.getTime().getTime() / 1000L) - (c2.getTime().getTime() / 1000L)) / 86400L);
	}

	/**
	 * 
	* @Title: compareDate
	* @Description: 日期比较大小 [0:date1 = date2] [1:date1 > date2] [-1:date1 < date2]
	* @param date1
	* @param date2
	* @return    参数
	* @return int    返回类型
	 */
	public static int compareDate(String date1, String date2) {
		Date date1d = parse(date1);
		Date date2d = parse(date2);
		if (date1d.after(date2d))
			return 1;
		if (date1d.before(date2d))
			return -1;
		else
			return 0;
	}
	/**
	 * 
	* @Title: compareDateHighScale
	* @Description: 日期比较大小 ，指定格式
	* @param date1
	* @param date2
	* @return    参数
	* @return int    返回类型
	* @throws
	 */
	public static int compareDateHighScale(String date1, String date2) {
		Date date1d = parseHighScale(date1);
		Date date2d = parseHighScale(date2);
		if (date1d.after(date2d)) {
			return 1;
		}
		if (date1d.before(date2d)) {
			return -1;
		} else {
			return 0;
		}
	}

	/**
	 * 
	* @Title: getRelativeDate
	* @Description:  获得与某日期相差指定（日/月/年）的日期
	* @param date 当前日期
	* @param dateUnit 日期单位：Calendar.DATE/Calendar.MONTH/Calendar.YEAR
	* @param num
	* @return    参数
	* @return String    返回类型
	 */
	public static String getRelativeDate(String date, int dateUnit, int num) {
		if (num == 0)
			return date;
		Calendar cal = Calendar.getInstance();
		SimpleDateFormat format = new SimpleDateFormat(SIMPLE_FORMAT);
		try {
			cal.setTime(format.parse(date));
			cal.add(dateUnit, num);
		} catch (Exception e) {
			throw new RuntimeException("日期运算异常", e);
		}
		return format.format(cal.getTime());
	}

	/**
	 * 
	* @Title: getEndDateOfMonth
	* @Description: 得到月底
	* @param curDate
	* @return    参数
	* @return String    返回类型
	 */
	public static String getEndDateOfMonth(String curDate) {
		if (curDate == null || curDate.length() != 8) {
			return null;
		}
		curDate = curDate.substring(0, 6) + "01";
		Calendar cal = Calendar.getInstance();
		SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
		try {
			cal.setTime(format.parse(curDate));
		} catch (ParseException e) {
			throw new RuntimeException(e.getMessage());
		}
		int maxDays = cal.getActualMaximum(Calendar.DATE);// 得到该月的最大天数
		cal.set(Calendar.DATE, maxDays);
		return format.format(cal.getTime());
	}

	/**
	 * 
	* @Title: getNextPaydate
	* @Description: 获取传入日期指定默认日期，判断是否大于二月最大一天
	* @param nextDate
	* @param defaultDate
	* @return    参数
	* @return String    返回类型
	 */
	public static String getNextPaydate(String nextDate, String defaultDate) {
		if (defaultDate.compareTo("28") > 0) {
			nextDate = nextDate.substring(0, 6) + defaultDate;
			String tmp = DateUtil.getEndDateOfMonth(nextDate);
			if (tmp != null && tmp.compareTo(nextDate) < 0) {
				nextDate = tmp;
			}
		}
		return nextDate;
	}
	

	/**
	 * 
	* @Title: getTimeAfter
	* @Description: 获得指定单位时间后的日期，传入afterTime为基础，field为单位，计算amount后的时间
	* @param afterTime
	* @param field 单位
	* @param amount
	* @return    参数
	* @return Date    返回类型
	 */
	public static Date getTimeAfter(Date afterTime, int field, int amount) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(afterTime);
		calendar.add(field, amount);
		return calendar.getTime();
	}

	/**
	 * 
	* @Title: getTimeAfter
	* @Description: 传入afterTime为基础，计算出下个符合cron串的时间
	* @param afterTime
	* @param cron
	* @return
	* @throws ParseException    参数
	* @return Date    返回类型
	 */
	public static Date getTimeAfter(Date afterTime, String cron) {
		CronSequenceGenerator cronSequenceGenerator = new CronSequenceGenerator(cron);
		return cronSequenceGenerator.next(afterTime);

	}

	/**
	 * 
	 * @Title: getCurrentDate
	 * @Description: 获取当前日期(yyyy-MM-dd HH:mm:ss)
	 * @param @return
	 *            参数
	 * @return String 返回类型
	 */
	public static String getCurrentDate() {
		SimpleDateFormat format = new SimpleDateFormat(HIGH_SCALE_FORMAT);
		String currentDate = format.format(new Date().getTime());
		return currentDate;
	}

	/**
	 * 获取两个日期之间的间隔月数 str1 - str2 = ?
	 * 
	 * @return 间隔月数
	 * @throws ParseException
	 */
	public static int getMonthBetween(String str1, String str2) {
		Calendar c1 = Calendar.getInstance(Locale.CHINA);
		Calendar c2 = Calendar.getInstance(Locale.CHINA);
		c1.setTime(parse(str1));
		c2.setTime(parse(str2));
		// 把时分秒置为0
		c1.set(Calendar.HOUR_OF_DAY, 0);
		c1.set(Calendar.MINUTE, 0);
		c1.set(Calendar.SECOND, 0);

		c2.set(Calendar.HOUR_OF_DAY, 0);
		c2.set(Calendar.MINUTE, 0);
		c2.set(Calendar.SECOND, 0);
		return (int) (c1.get(Calendar.YEAR) - c2.get(Calendar.YEAR)) * 12 + c1.get(Calendar.MONTH)
				- c2.get(Calendar.MONTH);
	}
	
	/**
	 * 
	 * @Title: getAllTheMonthsInTheCurrentYearget
	 * @Description: 获取当前年当前时间前的所有的月份
	 * @return 参数
	 * @return List<String> 返回类型
	 */
	public static List<String> getAllTheMonthsInTheCurrentYearget() {
		List<String> list = new ArrayList<String>();
		try {
			Calendar dd = Calendar.getInstance();// 定义日期实例
			SimpleDateFormat format = new SimpleDateFormat("yyyy-MM");
			String nowdate = format.format(new Date());// 当前月份
			String year = String.valueOf(dd.get(Calendar.YEAR));
			Date d1 = new SimpleDateFormat("yyyy-MM").parse(year + "-01");// 定义起始日期
			Date d2 = new SimpleDateFormat("yyyy-MM").parse(nowdate);// 定义结束日期 可以去当前月也可以手动写日期。
			dd.setTime(d1);// 设置日期起始时间
			while (dd.getTime().before(d2)) {// 判断是否到结束日期
				SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
				String str = sdf.format(dd.getTime());
				list.add(str);
				dd.add(Calendar.MONTH, 1);// 进行当前日期月份加1

			}
			list.add(nowdate);
			return list;

		} catch (Exception e) {
			log.error("获取当前年当前时间前的所有的月份,异常", e);
		}
		return list;
	}
   
	/**
	 * 
	 * @Title: getTheMonthBeforeTheCurrentTime
	 * @Description: 获取当前时间前一段时间的月份
	 * @param num
	 * @return 参数
	 * @return List<String> 返回类型
	 */
	public static List<String> getTheMonthBeforeTheCurrentTime(int num) {
		List<String> list = new ArrayList<String>();
		if (num > 0) {
			try {
				Calendar dd = Calendar.getInstance();// 定义日期实例
				SimpleDateFormat format = new SimpleDateFormat("yyyy-MM");
				String nowdate = format.format(new Date());// 当前月份
				Date d = new SimpleDateFormat("yyyy-MM").parse(nowdate);// 定义结束日期 可以去当前月也可以手动写日期。
				dd.setTime(d);// 设置日期起始时间
				for (int i = 0; i < num; i++) {
					SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
					String str = sdf.format(dd.getTime());
					dd.add(Calendar.MONTH, -1);// 进行当前日期月份加-1
					list.add(str);
				}
				Collections.reverse(list);
				return list;

			} catch (Exception e) {
				log.error("获取当前时间前一段时间的月份,异常", e);
			}
		}
		return list;
	}
	
	/**
	 * 
	 * @Title: getTheYearBeforeTheCurrentTime
	 * @Description: 获取当前时间前一段时间的年份
	 * @param num
	 * @return 参数
	 * @return List<String> 返回类型
	 */
	public static List<String> getTheYearBeforeTheCurrentTime(int num) {
		List<String> list = new ArrayList<String>();
		if (num > 0) {
			try {
				Calendar dd = Calendar.getInstance();// 定义日期实例
				SimpleDateFormat format = new SimpleDateFormat("yyyy");
				String nowdate = format.format(new Date());// 当前年
				Date d = new SimpleDateFormat("yyyy").parse(nowdate);// 定义结束日期 可以去当前月也可以手动写日期。
				dd.setTime(d);// 设置日期起始时间
				for (int i = 0; i < num; i++) {
					SimpleDateFormat sdf = new SimpleDateFormat("yyyy");
					String str = sdf.format(dd.getTime());
					dd.add(Calendar.YEAR, -1);// 进行当前日期月份加-1
					list.add(str);
				}
				return list;

			} catch (Exception e) {
				log.error("获取当前时间前一段时间的年份,异常", e);
			}
		}
		return list;
	}
	
	/**
	 * 
	 * @Title: getDateIntervalList 
	 * @Description: 获取指定日期段间每一天详细信息，周、日期、星期 
	 * @param beginDate 开始日期 yyyymmdd
	 * @param endDate 结束日期 yyyymmdd
	 * @param    设定文件 
	 * @return Map<String,Object>    返回类型 
	 */
	public static List<HashMap<String,Object>> getDateIntervalList(String beginDate, String endDate){
		int beginYer=Integer.parseInt(beginDate.substring(0, 4));
		int beginMonth=Integer.parseInt(beginDate.substring(4, 6))-1;
		int beginDay=Integer.parseInt(beginDate.substring(6, 8));
		int endYer=Integer.parseInt(endDate.substring(0, 4));
		int endMonth=Integer.parseInt(endDate.substring(4, 6))-1;
		int endDay=Integer.parseInt(endDate.substring(6, 8));
		List<HashMap<String,Object>> list=new ArrayList<HashMap<String,Object>>();
		Calendar caBegin = new GregorianCalendar();
		Calendar caEnd = new GregorianCalendar();
		DateFormatSymbols dfs = new DateFormatSymbols(); 
		String[] weeks = dfs.getWeekdays();

		caBegin.set(beginYer, beginMonth, beginDay); //Calendar的月从0-11，所以4月是3.
		caEnd.set(endYer, endMonth, endDay); //Calendar的月从0-11，所以5月是4.

		int count = 1;
		caEnd.add(Calendar.DAY_OF_YEAR, 1);  //结束日期下滚一天是为了包含最后一天

		while(caBegin.before(caEnd)){
			HashMap<String, Object> map=new HashMap<String, Object>();
			map.put("ORDER", count);
			map.put("DATE", new java.sql.Date(caBegin.getTime().getTime()));
			map.put("WEEK", weeks[caBegin.get(Calendar.DAY_OF_WEEK)]);
			list.add(map);
			if(caBegin.get(Calendar.DAY_OF_WEEK)==Calendar.SUNDAY){
				count++;
			}
			caBegin.add(Calendar.DAY_OF_YEAR, 1);
		}
		return list;
	}
	

}
